home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / wais / waisgate / server.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  22KB  |  753 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE    
  2.    No guarantees or restrictions.  See the readme file for the full standard 
  3.    disclaimer.
  4.    5.29.90    Harry Morris, morris@think.com
  5. */
  6.  
  7. /* this file is a server process for a unix machine that takes input from 
  8.    standard in or from a socket and searches the local search engine on the 
  9.    unix box.
  10.    originally written by harry morris.
  11.    modified by brewster kahle. 7/90
  12.    6.xx.90    Brewster - initial implementation of stdio interface
  13.    7.xx.90    Patrick Bray - support for headers and forking processes
  14.    90.07.31    Ephraim - support for logging 
  15.  
  16.    91.03.03     Jonathan - set searchLog to log_out.
  17.    91.05.23    Jonathan - added fork process for indexer.
  18.                            Fixed version display so it exits.
  19.    91.05.25     Jonathan - added setuid.
  20.    
  21.    Tue Jul  9 12:11:02 1991 -- Michael Haberler mah@wu-wien.ac.at
  22.  
  23.                 Added semi-intelligent INFO database indexing (only done if
  24.         any of the .src files is newer than INFO.dct)
  25.         
  26.         Locking against multiple concurrent INFO rebuilds if 
  27.         running under inetd
  28.  
  29.         Use scandir() for directory operations
  30.  
  31.         Works under inetd as well as standalone. Here are my inetd.conf
  32.            entries (not the missing userid in the Ultrix inetd.conf!):
  33.  
  34.    hpux 7.0/800, Interactive/386 2.2.1:
  35.     z3950 stream tcp nowait root /usr/local/etc/waisserver waisserver -s \
  36.         -d /usr/logins/mah/wais-sources
  37.  
  38.    Ultrix 4.1:
  39.     z3950 stream tcp nowait /usr/local/etc/waisserver waisserver -s \
  40.         -d /usr/logins/mah/wais-sources
  41.  
  42.    Also, add the next line to /etc/services, and tickle your YP server:
  43.     z3950           210/tcp         # wide area information server (wais)
  44.  
  45.  * $Log: server.c,v $
  46.  * Revision 1.48.1.1  1992/07/11  01:03:51  curtisg
  47.  * Changes for SCO UNIX
  48.  *
  49.  * Revision 1.48  92/05/10  14:47:39  jonathan
  50.  * Update for release.
  51.  * 
  52.  * Revision 1.47  92/05/06  17:34:01  jonathan
  53.  * Changed auto-indexing of .src files to use filename_finish_header_function.
  54.  * 
  55.  * Revision 1.46  92/05/04  17:18:32  jonathan
  56.  * Fixed use of merge_pathname in creating INFO database.
  57.  * 
  58.  * Revision 1.45  92/04/28  15:19:18  jonathan
  59.  * Added decoding of IP address to DNS name in init message handler.
  60.  * 
  61.  * Revision 1.44  92/03/26  18:26:41  jonathan
  62.  * Added extra arguments to index_text_file call.
  63.  * 
  64.  * Revision 1.43  92/03/07  19:41:47  jonathan
  65.  * Added IBM defines, courtesy mycroft@hal.gnu.ai.mit.edu,
  66.  * 
  67.  * Revision 1.42  92/03/05  07:07:58  shen
  68.  * add two more dummy arguments to call to init_search_engine
  69.  * 
  70.  * Revision 1.41  92/02/27  09:58:50  jonathan
  71.  * Put back in setting of core limit to max value, when SET_LIMIT is defined.
  72.  * 
  73.  * Revision 1.40  92/02/24  10:07:41  jonathan
  74.  * Removed reporting functions.
  75.  * 
  76.  * Revision 1.39  92/02/21  12:27:15  jonathan
  77.  * Changed logging of segmentation violation and bus errors to mark log with
  78.  * an error code, and close code.
  79.  * 
  80.  * Revision 1.38  92/02/21  11:00:45  jonathan
  81.  * Added wais_log_level
  82.  * 
  83.  * Revision 1.37  92/02/19  10:16:25  jonathan
  84.  * Added build_catalog to auto-indexer.
  85.  * 
  86.  * Revision 1.36  92/02/16  12:33:21  jonathan
  87.  * Removed code refering to NOINETNTOA, since we should use inet_ntoa.
  88.  * 
  89.  * Revision 1.35  92/02/16  12:05:18  jonathan
  90.  * Added code for GCC incompatibility in inet_ntoa (passing structure as
  91.  * pointer).
  92.  * 
  93.  * Revision 1.34  92/02/14  09:07:34  jonathan
  94.  * Set MAXNAPTIME to 0 so it won't sleep.  Changed the WLOG_ERROR to
  95.  * WLOG_WARNING in the log entry.
  96.  * 
  97.  * Revision 1.33  92/02/12  13:44:20  jonathan
  98.  * Added "$Log" so RCS will put the log message in the header
  99.  * 
  100.  * 
  101.  */
  102.  
  103. #define SERVER_DATE "Sun May 10 1992"
  104.  
  105. #ifndef lint
  106. static char *RCSid = "$Header: /y/src/wais/wais-8-b5/ir/RCS/server.c,v 1.48.1.1 1992/07/11 01:03:51 curtisg Exp curtisg $";
  107. #endif
  108.  
  109. #define INFO_DICT    "INFO.dct"
  110. #define LOCKFILE    "/tmp/INFO.lock" /* while re-indexing INFO */
  111. #define NAPTIME     1             /* seconds */
  112. #define MAXNAPTIME  0        /* Don't wait, just go on. */
  113.  
  114. #include "server.h"
  115. #include "sockets.h"
  116. #include <sys/types.h>
  117. #include <sys/stat.h>
  118. #ifdef ultrix
  119. #include <sys/file.h>
  120. #else
  121. #if defined(_IBMR2) || defined(M_UNIX)
  122. #include <fcntl.h>
  123. #else /* ! _IBMR2 */
  124. #ifdef USG
  125. #include <sys/fcntl.h>
  126. #else
  127. #include <sys/file.h>
  128. #endif
  129. #endif /* _IBMR2 */
  130. #endif /* else ultrix */
  131. #ifdef SYSV            
  132. #define SIGCHLD SIGCLD
  133. #endif
  134. #include <signal.h>
  135. #include <string.h>
  136. #include "irdirent.h"
  137. #include "panic.h"
  138. #include "ustubs.h"
  139. #include "transprt.h"
  140. #include "wmessage.h"
  141. #include "ir.h"
  142. #include "wprot.h"
  143. #include "cutil.h"
  144. #include "futil.h"
  145. #include "irext.h"
  146. #include "irsearch.h"
  147.  
  148. /* to create the INFO index */
  149. #include "irtfiles.h"
  150. #include "irfiles.h"
  151. #include "irhash.h"
  152. #include "version.h"
  153.  
  154. static long bufferSize = BUFSZ; /* how much we are using
  155.                                    (we get one of these per process) */
  156.  
  157. char *log_file_name = NULL;
  158.  
  159. FILE *logfile; /* the logfile */
  160.  
  161. /*---------------------------------------------------------------------------*/
  162.  
  163. #define TIMEOUT_LENGTH 36000 /* ten hour timeout. */
  164. #define IDLE_TIME "10 hours"
  165.  
  166. void
  167. serve_client(in,out, index_directory)
  168. FILE* in;
  169. FILE* out;
  170. char *index_directory;
  171.   char buf[BUFSZ];        /* contains the message and header */
  172.   char *bufPtr ;        /* points at the begining of the z3950 */
  173.   long size;            /* bytes in the z3950 message */
  174.   WAISMessage header;        /* for storing the header */
  175.   long i;
  176.   long bytesLeft;
  177.   struct itimerval new, old;
  178.   long nextChar;
  179.  
  180.   new.it_interval.tv_sec = 0;
  181.   new.it_interval.tv_usec = 0;
  182.   new.it_value.tv_sec = TIMEOUT_LENGTH;
  183.   new.it_value.tv_usec = 0;
  184.  
  185.   getitimer(ITIMER_REAL, &old);
  186.   while (TRUE)
  187.     {
  188.       /* try to read the header */
  189.       for (i = 0; i < HEADER_LENGTH; i++)
  190.     { 
  191.       setitimer(ITIMER_REAL, &new, NULL);
  192.       nextChar = fgetc(in);
  193.       if (nextChar == EOF)    /* my connection exited, so will I */
  194.         { 
  195.           return;
  196.         }
  197.       else
  198.         buf[i] = (char)nextChar;
  199.     }
  200.  
  201.       setitimer(ITIMER_REAL, &old, NULL);
  202.       /* parse the header */
  203.       readWAISPacketHeader(buf,&header);
  204.  
  205.       /* make sure we have the right version.  
  206.      If we dont, we dont know what to do. */
  207.       if (header.hdr_vers > HEADER_VERSION)
  208.     panic("Incompatable header versions (Current version: %c, supplied version: %c.", 
  209.           HEADER_VERSION, header.hdr_vers) ;
  210.  
  211.       /* determine the size of the z3950 message */
  212.       {
  213.     char length_array[11];
  214.     strncpy(length_array, header.msg_len, 10);
  215.     length_array[10] = '\0';
  216.     size = atol(length_array);
  217.       }
  218.  
  219.       /* set bufPtr to start the z3950 message */
  220.       bufPtr = buf + HEADER_LENGTH ;
  221.  
  222.       /* read the z3950 message */
  223.       for (i = 0; i < size ; i++) {
  224.     setitimer(ITIMER_REAL, &new, NULL);
  225.     buf[i + HEADER_LENGTH] = (char)fgetc(in) ;
  226.       }
  227.  
  228.       rewind(in);
  229.  
  230.       /* decode the z3950 if necessary */
  231.       transportDecode((long)header.encoding,bufPtr,&size);
  232.      
  233.       /* XXX handle compression options */
  234.  
  235.       /* process it the z3950 */
  236.       bytesLeft = bufferSize;
  237.  
  238.       size = interpret_buffer(bufPtr,size,bufPtr,bytesLeft,
  239.                   &bufferSize,(long)header.hdr_vers,
  240.                   index_directory); 
  241.  
  242.       /* re-encode the message if necessary */
  243.       transportCode((long)header.encoding,bufPtr,&size); 
  244.  
  245.       /* XXX handle compression options */
  246.  
  247.       /* write the new header */
  248.       writeWAISPacketHeader(buf,size,
  249.                 (long)header.msg_type,header.server,
  250.                 (long)header.compression,(long)header.encoding,
  251.                 (long)header.hdr_vers);
  252.  
  253.       /* write the whole response to the output file */
  254.       for (i = 0; i < size + HEADER_LENGTH; i++)
  255.     fputc(buf[i],out) ;
  256.  
  257.       fflush(out);        /* flush any file buffers */
  258.       rewind(out);        /* reset the file for read */
  259.  
  260.     }
  261. }
  262.  
  263. /*---------------------------------------------------------------------------*/
  264.  
  265. #ifndef ISC
  266. static void breakKey _AP((long s1,long s2,struct sigcontext* s3,char* s4));
  267. #endif
  268.  
  269. static void
  270. breakKey (s1,s2,s3,s4)
  271. long s1;
  272. long s2;
  273. struct sigcontext *s3;
  274. char *s4;
  275. {
  276.   if(0 != finished_search_engine())
  277.     panic("unable to close search engine");
  278.   panic ("got a ^c");
  279. }
  280.  
  281. /*---------------------------------------------------------------------------*/
  282.  
  283. void
  284. childhandler(sig, code, scp, addr)
  285. long sig, code;
  286. struct sigcontext *scp;
  287. char *addr;
  288. {
  289.   wait(NULL);            /* give the kid a decent burial */
  290. }
  291.  
  292. /*---------------------------------------------------------------------------*/
  293.  
  294. void
  295. alarmhandler(sig, code, scp, addr)
  296. long sig, code;
  297. struct sigcontext *scp;
  298. char *addr;
  299. {
  300.   waislog(WLOG_HIGH, WLOG_CLOSE,
  301.       "Server idle longer %s. Closing server and exiting.", IDLE_TIME);
  302.   if(0 != finished_search_engine())
  303.     panic("unable to close search engine");
  304.   exit(0);
  305. }
  306.  
  307. /*---------------------------------------------------------------------------*/
  308.  
  309. void
  310. seghandler(sig, code, scp, addr)
  311. long sig, code;
  312. struct sigcontext *scp;
  313. char *addr;
  314. {
  315.   waislog(WLOG_HIGH, WLOG_ERROR, "Segmentation violation.");
  316.   waislog(WLOG_HIGH, WLOG_CLOSE, "Bummer. Closing server and exiting.");
  317.   abort();
  318. }
  319.  
  320. /*---------------------------------------------------------------------------*/
  321.  
  322. void
  323. bushandler(sig, code, scp, addr)
  324. long sig, code;
  325. struct sigcontext *scp;
  326. char *addr;
  327. {
  328.   waislog(WLOG_HIGH, WLOG_ERROR, "Bus error.");
  329.   waislog(WLOG_HIGH, WLOG_CLOSE, "Bummer. Closing server and exiting.");
  330.   abort();
  331. }
  332.  
  333. /*---------------------------------------------------------------------------*/
  334.  
  335. #include <pwd.h>
  336.  
  337. int finduid(name)
  338. char *name;
  339. {
  340.   struct passwd *pwent;
  341.  
  342.   if ((pwent = getpwnam(name)) == NULL) {
  343.     return -1;
  344.   }
  345.  
  346.   return(pwent->pw_uid);
  347. }
  348.  
  349. static  char *index_dir = NULL;
  350. static  time_t info_change_time;
  351. static  int indexing_needed = 0;
  352. static  char *info_dict = INFO_DICT;
  353.  
  354. extern int alphasort();
  355.  
  356. /* selecttion function for scandir()
  357.  * trigger on ".src" extension, regular file, and != "INFO.src"
  358.  * Indexing is needed if any of the .src files is younger than 
  359.  * INFO.dct
  360.  */
  361. static int
  362. srcfiles(e)
  363.     struct dirent *e;
  364. {
  365.     struct stat sb;
  366.     char *lastdot = strrchr(e->d_name,'.');
  367.     int candidate;
  368.  
  369.     candidate =    lastdot && 
  370.           (stat(merge_pathnames(e->d_name,index_dir), &sb) >= 0) && 
  371.           ((sb.st_mode & S_IFMT) == S_IFREG) &&
  372.           !strcmp(lastdot,source_ext) && 
  373.           strcmp(e->d_name,info_dict); /* whew */
  374.  
  375.         if (candidate) {
  376.         indexing_needed |= (sb.st_mtime > info_change_time);
  377.         return 1;
  378.     }
  379.     return 0;
  380. }
  381.  
  382.  
  383. /*---------------------------------------------------------------------------*/
  384.  
  385. #ifdef SET_LIMIT
  386. #include <sys/resource.h>
  387. #endif
  388.  
  389. #define INDEX_FORK
  390.  
  391. extern char *inet_ntoa ();
  392.  
  393. void
  394. main(argc,argv)
  395. int argc;
  396. char* argv[];
  397. { FILE *file;
  398.   long socket;
  399.   char *next_argument = next_arg(&argc, &argv), *command_name;
  400.   boolean use_stdio = TRUE;        /* default is true */
  401.   /* char *log_file_name = NULL; */    /* name of file for error output */
  402.   int child_proc;        /* for the child process id */
  403.   char *uid_name = "root";    /* user id so setuid if root */
  404.   int uid = 0;        /* if not specified, leave as root. */
  405.   int child;
  406.   long cm_mem_percent = 0;  /* default */
  407.   struct stat statbuf;
  408.   struct dirent **list;
  409.   int naptime = 0;
  410.   extern int errno;
  411.   extern char *sys_errlist[];
  412.   char host_name[255], host_address[255];
  413.   extern void filename_finish_header_function();
  414.  
  415. #ifdef SET_LIMIT
  416.   struct rlimit rlp;
  417.  
  418.   getrlimit(RLIMIT_CORE, &rlp);
  419.   rlp.rlim_cur = rlp.rlim_max;
  420.   setrlimit(RLIMIT_CORE, &rlp);
  421. #endif
  422.  
  423.   tcp_port = 210;            /* tcp_port to use */
  424.   command_name = next_argument;
  425.   host_name[0] = 0;
  426.   host_address[0] = 0;
  427.  
  428.   server_name = s_malloc(255);
  429.   gethostname(server_name, 255);
  430.  
  431.   wais_pid = getpid();
  432.  
  433.   if (!strcmp(command_name, "waisserver.d")) {
  434.     struct sockaddr_in source;
  435.     int sourcelen;
  436.  
  437.     sourcelen = sizeof(struct sockaddr_in);
  438.  
  439.     if (!getpeername(fileno(stdout),&source,&sourcelen)) {
  440.       struct hostent *peer = NULL;
  441.  
  442.       peer = gethostbyaddr(&source.sin_addr, 4, AF_INET);
  443.  
  444.       if(peer != NULL)
  445.     sprintf(host_name, "%s", peer->h_name);
  446.  
  447.       sprintf(host_address, "%s",
  448. #if defined(sparc) && defined(__GNUC__)
  449.           inet_ntoa(&source.sin_addr)
  450. #else
  451.           inet_ntoa(source.sin_addr)
  452. #endif /* sparc */
  453.           );
  454.     }
  455.     else sprintf(host_address, "Error getting socket: %d, %s.", errno, sys_errlist[errno]);
  456.  
  457.     use_stdio = TRUE;
  458.   }
  459.  
  460.   if (argc == 0){
  461.     fprintf(stderr,"Usage: %s [-p [port_number]] [-s] [-d directory] [-u user] [-cmmem number] [-v]\n",
  462.        command_name);
  463.     fprintf(stderr," -p [port] listen to the port.  If the port is supplied, then\n");
  464.     fprintf(stderr,"    that tcp_port number is used.  If it is not supplied \n");
  465.     fprintf(stderr,"    then the Z39.50 port (210) is used.\n");
  466.     fprintf(stderr," -d directory: means to use the directory as the source of databases.\n");
  467.     fprintf(stderr,"    Defaults to the current directory.\n");
  468.     fprintf(stderr," -e [file]: set log output to file, or /dev/null if not specified.\n");
  469.     fprintf(stderr," -l log_level: set log level.  0 means log nothing,\n");
  470.     fprintf(stderr,"    10 [the default] means log everything.\n");
  471.     fprintf(stderr," -s means listen to standard I/O for queries.  This is the default\n");
  472.     fprintf(stderr," -u user: if started as root, setuid to user after startup.\n");
  473.     fprintf(stderr," -cmmem number: percentage of CM memory to use (CM code only).\n");
  474.     fprintf(stderr," -v prints the version.\n");
  475.     exit(1);
  476.   }
  477.   if(NULL == (next_argument = next_arg(&argc, &argv))){
  478.     fprintf(stderr,"No arguments specified\n");
  479.     exit(0);
  480.   }
  481.   while((next_argument != NULL) &&
  482.     ('-' == next_argument[0])){
  483.  
  484.     /* then we have an argument to process */
  485.     if (0 == strcmp("-p", next_argument)){
  486.       char *peek_argument = peek_arg(&argc, &argv);
  487.       use_stdio = FALSE;
  488.       if ((NULL != peek_argument) && /* if we are not out of args */
  489.       ('-' != peek_argument[0])){ { /* and the next isn't an option... */
  490.         /* get the port number */
  491.         tcp_port = atoi(next_arg(&argc, &argv));
  492.       }            /* end if (explicit tcp_port) */
  493.                     }
  494.     }                /* end if (-p) */
  495.     else if (0 == strcmp("-s", next_argument)){
  496.       use_stdio = TRUE;
  497.     }                /* end if (-s) */
  498.  
  499.     else if (0 == strcmp("-e", next_argument)) {
  500.       char *peek_argument = peek_arg(&argc, &argv);
  501.       log_file_name = "/dev/null"; /* default to /dev/null */
  502.       if ((peek_argument != NULL) &&
  503.       ('-' != peek_argument[0])) {
  504.     log_file_name = next_arg(&argc, &argv);
  505.       }                /* end if (explicit log file) */
  506.     }                /* end if (-e) */
  507.     else if (0 == strcmp("-l", next_argument)) {
  508.       wais_log_level = atol(next_arg(&argc, &argv));
  509.     }                /* end if (-l) */
  510.     else if (0 == strcmp("-d", next_argument)) {
  511.       index_dir = next_arg(&argc, &argv);
  512.     }
  513.     else if (0 == strcmp("-v", next_argument)) {
  514.       fprintf(stderr,"%s: %s, %s\n", command_name, VERSION, SERVER_DATE);
  515.     }
  516.     else if (0 == strcmp("-u", next_argument)) {
  517.       uid_name = next_arg(&argc, &argv);
  518.       if((uid = finduid(uid_name)) < 0)
  519.     panic("Couldn't find user %s.", uid_name);
  520.     }
  521.     else if(0 == strcmp("-cmmem", next_argument)){
  522.       if(NULL == (next_argument = next_arg(&argc, &argv)))
  523.     panic("Expected a number (1-100) for percentage of memory to use");
  524.       cm_mem_percent = atol(next_argument);
  525.       if(cm_mem_percent < 1)
  526.     panic("The -cmmem argument should not be less than 1 and less than 100");
  527.       if(cm_mem_percent > 100)
  528.     panic("Warning: The -cmmem parameter was %ld%%. It should be between 1-100.", cm_mem_percent);
  529.     }
  530.     else{
  531.       panic("Don't recognize the %s option", next_argument);
  532.     }
  533.     next_argument = next_arg(&argc, &argv);
  534.   }                /* end while (more arguments) */
  535.  
  536.   if (use_stdio && log_file_name == NULL) 
  537.     log_file_name = "/dev/null";
  538.  
  539.   if (log_file_name == NULL) 
  540.     logfile = stderr;
  541.   else logfile = NULL;
  542.   
  543.   index_dir = index_dir ? index_dir : ".";  
  544.   info_dict = s_strdup(merge_pathnames(info_dict,index_dir));
  545.  
  546.   if(0 != init_search_engine(index_dir, false, true, cm_mem_percent,0,0))
  547.     panic("unable to initialize search engine");
  548.   
  549.   /* remember timestamp on INFO.dct if rebuilding needed 
  550.    * If it doesnt exist, it's assumed to be *very* old, to force
  551.    * re-indexing
  552.    */
  553.   info_change_time = (stat(info_dict,&statbuf) == -1) ? 0 : statbuf.st_mtime;
  554.   
  555.   /* compare with candidates */
  556.  
  557.   if (scandir(index_dir, &list, srcfiles, alphasort) < 0) {
  558.       waislog(WLOG_HIGH, WLOG_ERROR, 
  559.           "Error: reading directory %s, %s", 
  560.           index_dir, sys_errlist[errno]);
  561.       indexing_needed = FALSE;
  562.   }
  563.   
  564.   /* ok. we know if we need indexing, 
  565.    * and have all the filenames. 
  566.    */
  567.   
  568.   if (info_change_time == 0) indexing_needed = TRUE;
  569.   if (indexing_needed) {
  570.  
  571.     /* Time to re-index,
  572.      * aquire the lock 
  573.      */
  574.     waislog(WLOG_MEDIUM, WLOG_INDEX,
  575.         "re-indexing needed, info_change_time=%d",info_change_time); 
  576.  
  577.     if (open(LOCKFILE, O_WRONLY|O_CREAT|O_EXCL,0666) == -1) {
  578.       
  579.       /* already locked by somebody else
  580.        * spin  till she finishes
  581.        */
  582.       while (!(stat(LOCKFILE,&statbuf) == -1)) {
  583.     sleep(NAPTIME);
  584.     naptime += NAPTIME;
  585.     waislog(WLOG_MEDIUM, WLOG_INFO,
  586.         "INFO locked, waiting since %d seconds", naptime);
  587.     if (naptime  > MAXNAPTIME)  {
  588.  
  589.       waislog(WLOG_HIGH, WLOG_WARNING,
  590.           "Warning - lockfile %s won't go away after %d seconds, not reindexing.", 
  591.           LOCKFILE, naptime);
  592.       break;
  593.     }
  594.       }
  595.       /* if lockfile went away, assume INFO.* build finished
  596.        * so just use it
  597.        */
  598.     } else {            /* we aquired the lock, so rebuild database  */
  599.       
  600. #ifdef INDEX_FORK
  601.       if (!(child = fork())) {
  602. #endif
  603.     database *db;
  604.     struct dirent **s = list;
  605.     char filename[MAX_FILENAME_LEN], *dbname;
  606.  
  607.     waislog(WLOG_MEDIUM, WLOG_INDEX,
  608.         "Creating INFO database, pid=%d",getpid());
  609.     dbname = s_strdup(merge_pathnames("INFO",    index_dir));
  610.     db = openDatabase(dbname, true, /* maybe this should append XXX */
  611.               false);
  612.     s_free(dbname);
  613.     init_add_word(db, 0, 100000L);
  614.  
  615.     while (*s) {        /* index it */
  616.       strncpy(filename, index_dir, MAX_FILENAME_LEN);
  617.       if(index_dir[strlen(index_dir) -1] != '/')
  618.         strncat(filename, "/", MAX_FILENAME_LEN);
  619.       strncat(filename, (*s)->d_name, MAX_FILENAME_LEN);
  620.       waislog(WLOG_MEDIUM, WLOG_INDEX,
  621.           "Indexing %s", filename);
  622.       index_text_file(filename, NULL, NULL, NULL, 
  623.               filename_finish_header_function,
  624.               "WSRC", db, true, false,
  625.               false, true);
  626.       s++;
  627.     }
  628.     freedir(list);        /* array of filenames */
  629.           
  630.     if(!probe_file(source_filename(filename, db)))
  631.       write_src_structure(source_filename(filename, db),
  632.                   "INFO", "WSRC", NULL, 0L, true, tcp_port);
  633.     finished_add_word(db);
  634.     build_catalog(db);
  635.     closeDatabase(db);
  636.     if (unlink(LOCKFILE))
  637.       panic("Indexer: cant unlink lockfile!\n");
  638.     waislog(WLOG_MEDIUM, WLOG_INDEX,
  639.         "Indexer pid=%d done", getpid());
  640.           
  641. #ifdef INDEX_FORK
  642.     exit(0);        /* indexing child */
  643.       }
  644.       else if (child == -1) {
  645.     waislog(WLOG_HIGH, WLOG_ERROR,
  646.         "Unable to fork for indexer.");
  647.     exit(1);
  648.       }
  649.       /* wait for child process */
  650.       else while (wait(0) != child) ; /* do nothing */
  651. #endif      
  652.     }
  653.   }
  654.  
  655.  
  656.   if (use_stdio == TRUE) {
  657.     if(host_address[0] != 0){
  658.       waislog(WLOG_MEDIUM, WLOG_CONNECT,
  659.           "Accepted connection from: %s [%s], %s",
  660.           host_name, host_address, VERSION);
  661.     }
  662.     else{
  663.       waislog(WLOG_MEDIUM, WLOG_CONNECT,
  664.           "Couldn't determine peer connection. %s", VERSION);
  665.     }
  666.   }
  667.   else{
  668.     waislog(WLOG_MEDIUM, WLOG_INFO, "Running server %s", VERSION);
  669.   }
  670.  
  671.   signal(SIGINT, breakKey);
  672.  
  673.   signal(SIGCHLD, childhandler);      /* XXX dont really need this any more */
  674.   signal(SIGALRM, alarmhandler);
  675.  
  676.   signal(SIGSEGV, seghandler);
  677.  
  678.   signal(SIGBUS, bushandler);
  679.  
  680.   if(use_stdio == FALSE)
  681.    { 
  682.      if (tcp_port < 1024 && getuid() != 0) {
  683.        waislog(WLOG_HIGH, WLOG_ERROR,
  684.            "Error opening port %d:  Must be superuser to use a port < 1024",
  685.            tcp_port);
  686.        exit(-1);
  687.      }
  688.  
  689.      open_server(tcp_port,&socket,BUFSZ);
  690.  
  691. #ifdef SECURE_SERVER
  692.      /* if root, setuid to user specified id. */
  693.      if (uid > 0 && getuid() == 0)  {
  694.        waislog(WLOG_MEDIUM, WLOG_INFO,
  695.            "Setting uid to %s.", uid_name);
  696.        if (chown(log_file_name,uid,getgid()) < 0)
  697.      waislog(WLOG_HIGH, WLOG_ERROR,
  698.          "Unable to chown log file to %s!", uid_name);
  699.        if ( 0 > setuid(uid)) {
  700.      waislog(WLOG_HIGH, WLOG_ERROR,
  701.          "Unable to setuid to %s!  Exiting.", uid_name);
  702.      exit(-1);
  703.        }
  704.      }
  705. #endif
  706.      while (TRUE) { /* be a server for several connections */
  707.        accept_client_connection(socket,&file);
  708.       
  709.        if ((child_proc = fork()) == 0) {
  710.           
  711.           /* grandson handles this connection
  712.            * double-fork takes care of zombies 
  713.            */
  714.           if ((child_proc = fork()) == 0) { 
  715.         wais_pid = getpid();
  716.         log_line = 0;
  717.         serve_client(file, file, index_dir);
  718.         /* but leaves server up */
  719.         close_client_connection(file);
  720.         close_server(socket);
  721.         /* just exits this child */
  722.         waislog(WLOG_MEDIUM, WLOG_CLOSE,
  723.             "Done handling client");
  724.         exit(0);
  725.           } else {
  726.         /* son: orphans the grandchild, so init picks up 
  727.          * the exit status
  728.          */
  729.         exit(0);
  730.           }
  731.           } else {
  732.           waislog(WLOG_MEDIUM, WLOG_INFO,
  733.               "Child PID = %d", child_proc);
  734.           close_client_connection(file);     /* parent shouldn't keep the file */
  735.       }
  736.       }
  737.    }
  738.   else if(use_stdio == TRUE)
  739.    { /* connections on stdio don't use child processes yet */
  740.      serve_client(stdin, stdout, index_dir);
  741.      waislog(WLOG_MEDIUM, WLOG_CLOSE,
  742.          "Done handling client");
  743.       /* close the whole thing */
  744.      if(0 != finished_search_engine())
  745.        panic("unable to close search engine");
  746.      exit(0);
  747.    }
  748. }
  749.  
  750. /*---------------------------------------------------------------------------*/
  751.  
  752.